package study.week03.gateway_final.outbound;

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpUtil;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import study.week03.gateway_final.filter.CustomHttpFilter;
import study.week03.gateway_final.router.CustomRouter;
import study.week03.uti.HttpClientUtil;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.*;

import static io.netty.handler.codec.http.HttpHeaderNames.CONNECTION;
import static io.netty.handler.codec.http.HttpHeaderValues.KEEP_ALIVE;
import static io.netty.handler.codec.http.HttpResponseStatus.NO_CONTENT;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;

public class OutboundHandler {
    private CustomHttpFilter[] filterChain ;
    private List<String> serverList;
    CustomRouter router;
    private ExecutorService proxyService;
    public OutboundHandler(CustomHttpFilter[] filterChain, List<String> serverList, CustomRouter router) {
        this.filterChain = filterChain;
        this.serverList = serverList;
        this.router = router;
        int cores = Runtime.getRuntime().availableProcessors();
        long keepAliveTime = 1000;
        int queueSize = 2048;
        RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();//.DiscardPolicy();
        proxyService = new ThreadPoolExecutor(cores, cores,
                keepAliveTime, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(queueSize), handler);
    }

    public void execute(ChannelHandlerContext ctx, FullHttpRequest fullRequest){
        proxyService.execute(()->{handleRequest(ctx,fullRequest);});
    }

    public void handleRequest(ChannelHandlerContext ctx, FullHttpRequest fullRequest){
        String uri = fullRequest.uri();
        String server = router.route(serverList);
        String target = server+uri;
        String body = "business server error.";
        try {
            body = HttpClientUtil.httpGet(target);
        }catch (Exception ex){
            ex.printStackTrace();
        }
        handleResponse(fullRequest,ctx,body);

    }
    /**
     * 过滤器链拒绝请求时的统一处理
     * @param fullRequest
     * @param ctx
     */
    private void handleResponse(FullHttpRequest fullRequest, ChannelHandlerContext ctx, String body ) {
        FullHttpResponse response = null;
        try {
            response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(body.getBytes(StandardCharsets.UTF_8)));
            response.headers().set("Content-Type", "application/json");
            response.headers().setInt("Content-Length", response.content().readableBytes());
        } catch (Exception e) {
            System.out.println("处理出错:"+e.getMessage());
            response = new DefaultFullHttpResponse(HTTP_1_1, NO_CONTENT);
        } finally {
            if (fullRequest != null) {
                boolean refuse = false;
                for (int i = filterChain.length -1; i >=0 ; i--) {
                    if(!filterChain[i].outbound(response)){
                        //过滤器返回false就结束请求
                        outboundRefuse(fullRequest,ctx);
                        refuse = true;
                        break;
                    }
                }
                if(!refuse){
                    if (!HttpUtil.isKeepAlive(fullRequest)) {
                        ctx.write(response).addListener(ChannelFutureListener.CLOSE);
                    } else {
                        response.headers().set(CONNECTION, KEEP_ALIVE);
                        ctx.write(response);
                    }
                    ctx.flush();
                }
            }
        }
    }
    /**
     * 过滤器链拒绝请求时的统一处理
     * @param fullRequest
     * @param ctx
     */
    private void outboundRefuse(FullHttpRequest fullRequest, ChannelHandlerContext ctx) {
        FullHttpResponse response = null;
        try {
            String body = "outbound filter refuse.";

            response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(body.getBytes(StandardCharsets.UTF_8)));
            response.headers().set("Content-Type", "application/json");
            response.headers().setInt("Content-Length", response.content().readableBytes());

        } catch (Exception e) {
            System.out.println("处理出错:"+e.getMessage());
            response = new DefaultFullHttpResponse(HTTP_1_1, NO_CONTENT);
        } finally {
            if (fullRequest != null) {
                if (!HttpUtil.isKeepAlive(fullRequest)) {
                    ctx.write(response).addListener(ChannelFutureListener.CLOSE);
                } else {
                    response.headers().set(CONNECTION, KEEP_ALIVE);
                    ctx.write(response);
                }
                ctx.flush();
            }
        }
    }


}
